﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;

/// <summary>
/// 简易生成器使用说明：
/// （1）如果是随机生成的话，会按照设定的可能生成概率来随机生成
///         假如随机物体A的生成可能性为4，随机物体B生成可能性为1
///         那么随机物体A生成的概率为4/5，随机物体B生成的概率为1/5
///         以此类推
/// （2）如果是规律生成的话，会按照一定规律来生成物体
///         比方说设置规律物体A生成的间隔为1，既是每间隔一个随机物体生成一个规律物体A
///         于是就会在第2，4，6，8等位置生成规律物体A
///         假如还有一个规律物体B生成间隔为3，既是每间隔三个随机物体生成一个规律物体B
///         此时会在第4，8，12等位置优先生成规律物体B，而不会生成规律物体A
///         又假如又有一个规律物体C生成间隔为3，既是每间隔三个随机物体生成一个规律物体C
///         此时由于规律物体B比规律物体C先添加，于是只会生成规律物体B，而不会生成C
/// </summary>
public class EasySpawner : MonoBehaviour
{
    [Tooltip("X轴开始生成位置")]
    public float startSpawnPosX = 0;
    [Tooltip("Z周开始生成位置")]
    public float startSpawnPosZ = 0;
    [Tooltip("基于摄像机的生成范围，该值过大会消耗更多的资源，除非摄像机移动速度快，否则保持适当值最好")]
    [Range(0, 100)]
    public int spawnRange = 25;
    [Tooltip("用于生成的物品")]
    public EasyItem[] items;

    #region 私有变量
    private Camera cam;
    private bool canSpawn = true;
    private Vector3 spawnPos;
    private int spawnCount = 0;

    private bool allowSpawn = false;

    private List<EasyItem> randomItemList = new List<EasyItem>();
    private List<EasyItem> regularItemList = new List<EasyItem>();
    private Queue<GameObject> recycleItemQueue = new Queue<GameObject>();
    #endregion

    void Awake()
    {
        Initialize();
    }

    void OnEnable()
    {
        GameManager.Instance.OverEvents += StopSpawn;
        GameManager.Instance.ResetEvents += Reset;
    }

    void OnDisable()
    {
        GameManager.Instance.OverEvents -= StopSpawn;
        GameManager.Instance.ResetEvents -= Reset;
    }

    void Update()
    {
        Spawn();
        Recycle();
    }

    #region 方法
    private void Initialize()
    {
        cam = FindObjectOfType(typeof(Camera)) as Camera;

        spawnPos.x = startSpawnPosX;
        spawnPos.z = startSpawnPosZ;

        foreach (var item in items)
        {
            if (item.Item == null)
            {
                GameObject ob = new GameObject("Empty");
                Debug.LogWarning("警告：EasySpawner中有一项物体为空，已自动补上空物体，建议手动补上");
                item.Item = ob;
            }
            switch (item.itemType)
            {
                case EasyItem.ItemType.random:
                    for (int i = 0; i < item.Probability; i++)
                    {
                        randomItemList.Add(item);
                    }
                    break;
                case EasyItem.ItemType.regular:
                    regularItemList.Add(item);
                    break;
            }

            if (item.ItemLength == 0)
            {
                if (item.Item.GetComponent<SpriteRenderer>() != null)
                {
                    item.ItemLength = item.Item.GetComponent<SpriteRenderer>().bounds.size.x;
                }
                else
                {
                    item.ItemLength = 1;
                }
            }
        }

        if (randomItemList.Count == 0 && regularItemList.Count == 0)
        {
            Debug.LogWarning("警告：有个EasySpawner没有添加任何生成物体！");
        }

        regularItemList.Sort();
    }
    private void Spawn()
    {
        if (!allowSpawn) return;
        if (randomItemList.Count == 0 && regularItemList.Count == 0) return;
        if ((spawnPos.x - cam.transform.position.x) <= spawnRange && canSpawn)
        {
            canSpawn = false;

            if (regularItemList.Count != 0)
            {
                foreach (var item in regularItemList)
                {
                    if (spawnCount % item.SpawnInterval == 0)
                    {
                        SpawnItem(item);
                        canSpawn = true;
                        break;
                    }
                }
            }
            if (!canSpawn)
            {
                int randomValue = Random.Range(0, randomItemList.Count);
                SpawnItem(randomItemList[randomValue]);
                canSpawn = true;
            }
        }
    }
    private void Recycle()
    {
        if (recycleItemQueue.Count != 0)
        {
            if ((recycleItemQueue.Peek().transform.position.x - cam.transform.position.x) <= -spawnRange)
            {
                Destroy(recycleItemQueue.Dequeue());
            }
        }
    }
    private void SpawnItem(EasyItem item)
    {
        spawnPos.y = item.OffsetY;
        spawnPos.x += item.ItemLength / 2;
        GameObject ob = Instantiate(item.Item, spawnPos, Quaternion.identity) as GameObject;
        spawnPos.x += item.ItemLength / 2;
        recycleItemQueue.Enqueue(ob);
        spawnCount++;
    }
    #endregion

    public void StopSpawn()
    {
        allowSpawn = false;
    }

    public void Reset()
    {
        while (recycleItemQueue.Count != 0)
        {
            Destroy(recycleItemQueue.Dequeue());
        }

        spawnPos.x = startSpawnPosX;
        spawnCount = 0;
        allowSpawn = true;
    }

}
